package object.obj2D.graphics;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import system.Device;
import system.Graphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;

public class Texture {
	private GL10 gl = (GL10) Graphics.GetGraphics();
	private Context m_context = Device.GetContext();
	private int m_textureID;
	private int m_height;
	private int m_width;
	// ------------------------------------------------------------
	// / Variable Declare
	// ------------------------------------------------------------
	public int[] m_convertSrcColor = null;
	public int[] m_convertDstColor = { 0x00000000 };
	public final int COLOR_ALL = -1;
	public final int COLOR_RED = 0xFFFF0000;
	public final int COLOR_GREEN = 0xFF00FF00;
	public final int COLOR_BLUE = 0xFF0000FF;

	// ------------------------------------------------------------
	// / Load texture into program
	// / @param the ID of texture
	// / @return
	// ------------------------------------------------------------
	public void loadTexture(int textureID) {
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
	}

	public void loadMipmapTexture(int textureID) {
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR_MIPMAP_NEAREST);
	}

	public void loadTexture() {
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
	}

	public void loadMipmapTexture() {
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR_MIPMAP_NEAREST);
	}

	// ------------------------------------------------------------
	// / initialize mipmap texture
	// / @param
	// / @return the ID of texture
	// ------------------------------------------------------------
	public void initTexture(String[] resName, int[] textureID, int max) {
		for (int i = 0; i < max; i++) {
			textureID[i] = this.initTexture(resName[i]);
		}
	}

	public int initMipmappedTexture(int resourceID) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
		Bitmap bitmap = loadBitmap(resourceID);
		buildMipmap(bitmap);
		bitmap.recycle();
		return m_textureID;
	}

	public int initMipmappedTexture(String resName) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
		Bitmap bitmap = loadBitmap(resName);
		buildMipmap(bitmap);
		bitmap.recycle();
		return m_textureID;
	}

	public int initMipmappedTexture(Bitmap bitmap) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
		buildMipmap(bitmap);
		bitmap.recycle();
		return m_textureID;
	}

	private void buildMipmap(Bitmap bitmap) {
		int level = 0;
		int height = bitmap.getHeight();
		int width = bitmap.getWidth();
		while (height >= 1 || width >= 1) {
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
			if (height == 1 || width == 1) {
				break;
			}
			level++;
			height /= 2;
			width /= 2;
			Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height,
					true);
			// Clean up
			bitmap.recycle();
			bitmap = bitmap2;
		}

	}

	// ------------------------------------------------------------
	// / initialize texture
	// / @param
	// / @return the ID of texture
	// ------------------------------------------------------------
	public int initTexture(Bitmap bitmap) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_NEAREST);
		
		return m_textureID;
	}

	public int initTexture(int resourceID) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		Bitmap bitmap = loadBitmap(resourceID);
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_NEAREST);
		bitmap.recycle();
		return m_textureID;
	}

	public int initTexture(String resName) {
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_textureID);
		Bitmap bitmap = loadBitmap(resName);
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_NEAREST);
		bitmap.recycle();
		return m_textureID;
	}

	// ------------------------------------------------------------
	// / Convert some color in srcColor into dstColor
	// / @param bitmap to convert, source Color, destination color
	// / @return the ID of texture
	// ------------------------------------------------------------
	public Bitmap ConvertColor(Bitmap srcBmp, int[] srcColor, int[] destColor) {
		int width = srcBmp.getWidth();
		int height = srcBmp.getHeight();
		int n = width * height;

		int[] array = new int[n];
		srcBmp.getPixels(array, 0, width, 0, 0, width, height);
		if (srcColor != null && destColor != null) {
			for (int i = 0; i < n; ++i) {
				for (int j = 0; j < srcColor.length; j++) {
					if (array[i] == srcColor[j]) {
						if (j < destColor.length)
							array[i] = destColor[j];
						else
							array[i] = destColor[destColor.length - 1];
					}
				}
			}
		}
		return Bitmap.createBitmap(array, width, height,
				Bitmap.Config.ARGB_8888);
	}

	public Bitmap ConvertColor(Bitmap srcBmp, int srcColor, int destColor) {
		int width = srcBmp.getWidth();
		int height = srcBmp.getHeight();
		int n = width * height;
		int[] array = new int[n];
		srcBmp.getPixels(array, 0, width, 0, 0, width, height);
		for (int i = 0; i < n; ++i) {
			if (array[i] == srcColor || (srcColor == COLOR_ALL && array[i] != 0X00000000)) {
				array[i] = destColor;
			}
		}
		return Bitmap.createBitmap(array, width, height,
				Bitmap.Config.ARGB_8888);
	}

	// ------------------------------------------------------------
	// / Load the bitmap
	// / @param the path of resource (image)
	// / @return this bitmap
	// ------------------------------------------------------------
	public Bitmap loadBitmap(String resName) {
		InputStream is = getClass().getResourceAsStream(resName);
		Bitmap bitmap;
		try {
			bitmap = BitmapFactory.decodeStream(is);
			bitmap = ConvertColor(bitmap, m_convertSrcColor, m_convertDstColor);
			this.m_width = bitmap.getWidth();
			this.m_height = bitmap.getHeight();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				// Ignore.
			}
		}
		return bitmap;
	}

	public Bitmap loadBitmap(int resourceID) {
		InputStream is = m_context.getResources().openRawResource(resourceID);
		Bitmap bitmap;
		try {
			bitmap = BitmapFactory.decodeStream(is);
			bitmap = ConvertColor(bitmap, m_convertSrcColor, m_convertDstColor);
			this.m_width = bitmap.getWidth();
			this.m_height = bitmap.getHeight();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				// Ignore.
			}
		}
		return bitmap;
	}
	public Bitmap createColorBitmap(int color){
		int [] arr = new int [] {color}; 
		return Bitmap.createBitmap(arr, 1, 1,
				Bitmap.Config.ARGB_8888);
	}
	public int  CaptureScreen(int screenWidth, int screenHeight) {
		byte [] byteTemp = new byte [screenWidth  * screenHeight * 4] ;
		ByteBuffer PBO = ByteBuffer.wrap(byteTemp);
		PBO.order(ByteOrder.nativeOrder());
	
		gl.glReadPixels(0, 0, screenWidth, screenHeight, 
				GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE,PBO);
		int[] textures = new int[1];
		gl.glGenTextures(1, textures, 0);
		m_textureID = textures[0];
		gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,
				screenWidth ,screenHeight ,0,
				GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, PBO);
		return m_textureID;
	}
	// ------------------------------------------------------------
	// / Getter and setter function
	// ------------------------------------------------------------
	public int getHeight() {
		return m_height;
	}

	public int getWidth() {
		return m_width;
	}

	public int getTextureID() {
		return m_textureID;
	}
}
